﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Casamiel.Common;
using Casamiel.Common.Extensions;
using Casamiel.Domain.Entity;
using Casamiel.Domain;
using Casamiel.Domain.Request;
using Casamiel.Domain.Response;
using Enyim.Caching;
using MediatR;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Casamiel.Application.Commands
{
    /// <summary>
    /// Create invoice command handler.
    /// </summary>
    public sealed class CreateInvoiceCommandHandler : BaseCommandHandler, IRequestHandler<CreateInvoiceCommand, BaseResult<string>>
    {
        private readonly IInvoiceDetailRepository _detailRepository;
        private readonly IInvoiceRepository _invoiceRepository;
        private readonly ICasaMielSession _session;
        private readonly IMemcachedClient _memcachedClient;
        private readonly InvoiceSettings _invoiceSettings;
        public CreateInvoiceCommandHandler(INetICService netICService, IOptionsSnapshot<CasamielSettings> casamielSettings, IOptionsSnapshot<InvoiceSettings> options, IInvoiceRepository invoiceRepository, IInvoiceDetailRepository detailRepository,
         ICasaMielSession casaMielSession, IHttpClientFactory httpClientFactory, IMemcachedClient memcachedClient) : base(netICService, httpClientFactory, casamielSettings)
        {
            _invoiceRepository = invoiceRepository;
            _detailRepository = detailRepository;
            _session = casaMielSession;

            _memcachedClient = memcachedClient;
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            _invoiceSettings = options.Value;
        }

        /// <summary>
        /// Handle the specified request and cancellationToken.
        /// </summary>
        /// <returns>The handle.</returns>
        /// <param name="request">Request.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        public async Task<BaseResult<string>> Handle(CreateInvoiceCommand request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            var list = await _detailRepository.GetListAsync<ICasaMielSession>(request.IDS, request.Mobile).ConfigureAwait(false);
            if (!list.Any())
            {
                return new BaseResult<string>("", 9999, "没有可开的记录");
            }
            var _cachekey = MemcachedPre + Constant.INVOICE + request.Mobile;
            var trynum = 0;                                                                                 //  trynum += _memcachedClient.GetWithCas<int>(_memcachedPrex + "Icselfregist" + mobile).Result;
            var da = new Enyim.Caching.Memcached.CasResult<object>();
            if (_memcachedClient.TryGetWithCas(_cachekey, out da))
            {
                trynum = (int)da.Result + 1;
                _memcachedClient.Cas(Enyim.Caching.Memcached.StoreMode.Replace, _cachekey, trynum);
            }
            else
            {
                trynum += 1;
                var resultss = _memcachedClient.Cas(Enyim.Caching.Memcached.StoreMode.Add, _cachekey, trynum);
            }
            if (trynum > 1)
            {
                _memcachedClient.Remove(_cachekey);
                return new BaseResult<string>("", 9999, "请不要重复提交");
            }
            var ordertotal = list.Sum(c => c.Amount);

		 var taxrate=	_invoiceSettings.Taxrate.ToDecimal(0);
		   var entity = new BaseInvoice
            {
                OrderNO = $"F{DateTime.Now.ToString("yyMMddHHmmssfff", System.Globalization.CultureInfo.CurrentCulture)}",
                OrderTotal = ordertotal,
                TaxTotal = decimal.Round((ordertotal / (1+ taxrate)) * taxrate, 2),
                Bhtaxtotal = decimal.Round((ordertotal / (1 + taxrate)), 2),
                Mobile = request.Mobile,
                Account = request.Account,
                Address = request.Address,
                BuyerName = request.BuyerName,
                SmsMobile = request.SmsMobile,
                TaxNum = request.TaxNum,
                CreateTime = DateTime.Now,
                Status = 1,
                Email = request.Email,
                InvoiceType = request.InvoiceType
            };
            await _invoiceRepository.SaveAsync<ICasaMielSession>(entity).ConfigureAwait(false);

            list.ForEach(x =>
            {
                x.Status = 0;
                x.Invoice_ID = entity.ID;
            });

            using (var uow = _session.UnitOfWork(IsolationLevel.Serializable))
            {
                await _detailRepository.UpdateByListAsync(list, uow).ConfigureAwait(false);
            }

            var tsfs = 0;//推送方式
            if (request.SmsMobile.Length > 10)
            {
                tsfs = 2;
            }
            var de = new List<TicketOpeningDetailReq>
            {
                  new TicketOpeningDetailReq {
                        taxfreeamt = $"{entity.Bhtaxtotal}",
                        tax = $"{entity.TaxTotal}",
                        Taxrate = _invoiceSettings.Taxrate,
                         taxamt =$"{ entity.OrderTotal}"
                }
            };
            string appToken = "bd481f06d2e19accab48965ada3b8f14d66d02b78b345d67908e4dc8f9d8860aefe0ad391d8963586632c4cba89bf64a";
            var data = new
            {
                orderno = entity.OrderNO,
                appToken,
                invoicedate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture),
                ordertotal = entity.OrderTotal,
                taxtotal = entity.TaxTotal,
                bhtaxtotal = entity.Bhtaxtotal,
                kptype = 1,
                clerk = _invoiceSettings.Clerk,
                address = entity.Address,
                tsfs,
                phone = string.IsNullOrEmpty(entity.SmsMobile) ? entity.Mobile : entity.SmsMobile,
                taxnum = entity.TaxNum,
                account = entity.Account,
                buyername = entity.BuyerName,
                email = entity.Email,
                detail = de
            };

            var result = await PostAsync("api/NuoNuoAPI/ElectronicInvoiceAPI/TicketOpening", JsonConvert.SerializeObject(data), "InvoiceApi").ConfigureAwait(false);
            var d = JsonConvert.DeserializeObject<JObject>(result);
            if (d["code"].ToString() != "0")
            {
                await Invoicefailer(list, entity).ConfigureAwait(false);
                _memcachedClient.Remove(_cachekey);
                return new BaseResult<string>("", 999, d["msg"].ToString());
            }
            else
            {
                var s = JsonConvert.DeserializeObject<JObject>(d["content"].ToString());
                if (s["status"].ToString() == "0000")
                {
                    entity.fpqqlsh = s["fpqqlsh"].ToString();
                    await _invoiceRepository.UpdateAsync<ICasaMielSession>(entity).ConfigureAwait(false);
                    _memcachedClient.Remove(_cachekey);
                    return new BaseResult<string>("", 0, "开票成功");
                }
                else
                {
                    await Invoicefailer(list, entity).ConfigureAwait(false);
                    BizInfologger.Error(s["message"].ToString());
                    _memcachedClient.Remove(_cachekey);
                    return new BaseResult<string>("", 999, s["message"].ToString());
                }
            }
        }

        private async Task Invoicefailer(List<InvoiceDetail> list, BaseInvoice entity)
        {
            list.ForEach(x =>
            {
                x.Status = 1;
                x.UpdateTime = DateTime.Now;
            });

            entity.Status = 0;
            using (var uow = _session.UnitOfWork(IsolationLevel.Serializable))
            {
                await _detailRepository.UpdateByListAsync(list, uow).ConfigureAwait(true);

                await _invoiceRepository.UpdateAsync(entity, uow).ConfigureAwait(true);
            }
        }
    }
}
